'''
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License") you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http:#www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
'''
from base.shared.DatatypeFormatException import DatatypeFormatException
from base.rdf.Literal import Literal
from base.rdf.ResourceRequiredException import ResourceRequiredException
from base.rdf.impl.Util import Util
from base.shared.BadBooleanException import BadBooleanException

#import org.apache.jena.JenaRuntime;
#import org.apache.jena.datatypes.DatatypeFormatException;
#import org.apache.jena.datatypes.RDFDatatype;
#import org.apache.jena.datatypes.xsd.XSDDatatype;
#import org.apache.jena.enhanced.*;
#import org.apache.jena.graph.*;
#import org.apache.jena.rdf.model.*;
#import org.apache.jena.shared.*;

'''
 * An implementation of Literal.
'''
from abc import ABC, abstractmethod

class LiteralImpl(Literal):

    # # param
    # # result Implementation factory = new
    # def Implementation factory = new Implementation(self):
    #     ##@Override
    # # param Node n, EnhGraph eg
    # # result boolean
    # def canWrap(self, n, eg):
    #         return n.isLiteral()
    #
    #
    #     ##@Override
    # # param Node n, EnhGraph eg
    # # result EnhNode
    # def wrap(self, n, eg):
    #         if (!n.isLiteral()) raise LiteralRequiredException(n)
    #         return new LiteralImpl(n, eg)
    #
    

    # param Node n, ModelCom m:
    def __init__(self, n, m):
        self.node = n
        self.model = m
        #super().__init__(n, m)
    

    # param Node n, EnhGraph m:
    # def __init__(self, nEnhGraph):
    #     super().__init__(n, m)
    

    ##@Override
    # param RDFVisitor rv
    # result Object
    # def visitWith(self, rv):
    #     return rv.visitLiteral(this)
    

    '''
     * Literals are not in any particular model, and so inModel can return this.
     *
     * @param m a model to move the literal into
     * @return this
    '''
    ##@Override
    # param Model m
    # result Literal
    def inModel(self, m):
        return self if self.model == m else m.getRDFNode(self.asNode())
                # ? this
                # : (Literal) m.getRDFNode(asNode())
                
    

    ##@Override
    # param 
    # result Literal
    def asLiteral(self):
        return self
    

    ##@Override
    # param 
    # result Resource
    def asResource(self):
        raise ResourceRequiredException(self.asNode())
    

    '''
     * Answer the model this literal was created in, if any, otherwise null.
    '''
    ##@Override
    # param 
    # result Model
    def getModel(self):
        #return (ModelCom) getGraph()
        return self.model
    

    ##@Override
    # param 
    # result String
    def toString(self):
        return self.asNode().toString()
    

    '''
     * Return the value of the literal. In the case of plain literals
     * this will return the literal string. In the case of typed literals
     * it will return a java object representing the value. In the case
     * of typed literals representing a java primitive then the appropriate
     * java wrapper class (Integer etc) will be returned.
    '''
    ##@Override
    # param 
    # result Object
    def getValue(self):
        return self.asNode().getLiteralValue()
    

    '''
     * Return the datatype of the literal. This will be null in the
     * case of plain literals.
    '''
    ##@Override
    # param 
    # result RDFDatatype
    def getDatatype(self):
        return self.asNode().getLiteralDatatype()
    

    '''
     * Return the uri of the datatype of the literal. This will be null in the
     * case of plain literals.
    '''
    ##@Override
    # param 
    # result String
    def getDatatypeURI(self):
        return self.asNode().getLiteralDatatypeURI()
    

    '''
     * Return true if this is a "plain" (i.e. old style, not typed) literal.
     * For RDF 1.1, the most compatible choice is "xsd:string" or "rdf:langString".
    '''
    # param 
    # result boolean
    def isPlainLiteral(self):
        #默认使用rdf 1.1
        #if (JenaRuntime.isRDF11)
            return Util.isLangString(self) or Util.isSimpleString(self)
        #else
            #return self.asNode().getLiteralDatatype() == null
    

    '''
     * Return the lexical form of the literal.
    '''
    ##@Override
    # param 
    # result String
    def getLexicalForm(self):
        return self.asNode().getLiteralLexicalForm()
    

    ##@Override
    # param 
    # result boolean
    def getBoolean(self):
        #Object 
        value = self.asNode().getLiteralValue()
        if (self.isPlainLiteral()):
            # old style plain literal - try parsing the string
            if (value.equals("true")):
                return True
            elif (value.equals("false")):
                return False
            else:
                raise BadBooleanException(value.toString())
            
        else:
            # typed literal
            if type(value) == bool:
                return value
            else:
                raise DatatypeFormatException(self.toString() + " is not a Boolean")
            
        
    

    ##@Override
    # param 
    # result byte
    def getByte(self):
        pass
        # if (isPlainLiteral()):
        #     return Byte.parseByte(self.getLexicalForm())
        # else:
        #     return byteValue(asNumber(getValue()))
        
    


    ##@Override
    # param 
    # result short
    def getShort(self):
        pass
        # if (isPlainLiteral()):
        #     return Short.parseShort(self.getLexicalForm())
        # else:
        #     return shortValue(asNumber(getValue()))
        
    

    ##@Override
    # param 
    # result int
    def getInt(self):
        if (self.isPlainLiteral()):
            return int(self.getLexicalForm())
        else:
            return self.getValue()
        
    

    ##@Override
    # param 
    # result long
    def getLong(self):
        return self.getInt()
        # if (isPlainLiteral()):
        #     return Long.parseLong(self.getLexicalForm())
        # else:
        #     return asNumber(getValue()).longValue()
        
    

    ##@Override
    # param 
    # result char
    def getChar(self):
        return self.getString()
        # if (isPlainLiteral()):
        #     if (getString().length() == 1):
        #         return (getString().charAt(0))
        #      else:
        #         raise BadCharLiteralException(getString())
        #     
        # else:
        #     Object value = getValue()
        #     if (value instanceof Character):
        #         return (Character) value
        #      else:
        #         raise DatatypeFormatException(value.toString() + " is not a Character")
            
        
    

    ##@Override
    # param 
    # result float
    def getFloat(self):
        if (self.isPlainLiteral()):
            return float(self.getLexicalForm())
        else:
            return self.getValue()
        
    

    ##@Override
    # param 
    # result double
    def getDouble(self):
        return self.getFloat()
        # if (isPlainLiteral()):
        #     return Double.parseDouble(self.getLexicalForm())
        # else:
        #     return asNumber(getValue()).doubleValue()
        
    

    ##@Override
    # param 
    # result String
    def getString(self):
        return self.asNode().getLiteralLexicalForm()
    

    ##@Override
    # param 
    # result String
    def getLanguage(self):
        return self.asNode().getLiteralLanguage()
    

    '''
     * @deprecated To be removed. Well-formness of XML literal is not tested for.
    '''
    ##@Override
    ##@Deprecated
    # param 
    # result boolean
    def isWellFormedXML(self):
        return self.asNode().getLiteralIsXML()
    

    '''
     * Test that two literals are semantically equivalent.
     * In some cases this may be the same as equals, in others
     * equals is stricter. For example, two xsd:int literals with
     * the same value but different language tag are semantically
     * equivalent but distinguished by the java equality function
     * in order to support round tripping.
    '''
    ##@Override
    # param Literal other
    # result boolean
    def sameValueAs(self, other):
        return self.asNode().sameValueAs(other.asNode())
    

    # Internal helper method to convert a value to number
    # param Object value
    # result Number
    def asNumber(self, value):
        pass
        # if (value instanceof Number):
        #     return ((Number) value)
        # else:
        #     StringBuilder message = new StringBuilder("Error converting typed value to a number. \n")
        #     message.append("Datatype is: " + getDatatypeURI())
        #     if (getDatatypeURI() == null or !getDatatypeURI().startsWith(XSDDatatypeInstances.XSD)):
        #         message.append(" which is not an xsd type.")
        #
        #     message.append(" \n")
        #     message.append("Java representation type is " + (value == null ? "null" : value.getClass().toString()))
        #     raise DatatypeFormatException(message.toString())
        
    

    # param Number n
    # result byte
    # def byteValue(self, n):
    #     return (byte) getIntegralValueInRange(Byte.MIN_VALUE, n, Byte.MAX_VALUE)
    

    # param Number n
    # result short
    # def shortValue(self, n):
    #     return (short) getIntegralValueInRange(Short.MIN_VALUE, n, Short.MAX_VALUE)
    

    # param Number n
    # result int
    # def intValue(self, n):
    #     return (int) getIntegralValueInRange(Integer.MIN_VALUE, n, Integer.MAX_VALUE)
    

    # param long min, Number n, long max
    # result long
    # def getIntegralValueInRange(self, min, n, max):
    #     long result = n.longValue()
    #     if (min <= result && result <= max) return result
    #     raise IllegalArgumentException("byte value required: " + result)
    


